package utils;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;
import constants.Configurations;
import constants.Default;
import play.Logger;
import play.Play;
import play.http.HTTP;
import play.http.Request;
import play.http.Response;
import org.apache.commons.lang3.StringUtils;
import protocol.SignedRequest;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;


public class DuppUtil {

    public static final ThreadLocal<StackTraceElement> invoker = new ThreadLocal<>();


    /**
     * 请求dupp组件接口后解析内容，返回data对象。
     * @param service
     * @param params
     * @param mute true=仅当异常时才会打印日志, false=全部日志
     * @return
     */
    public static JsonObject sendAndGetRaw(String service,String caller, Map<String, Object> params, boolean mute) {
        setInvoker();
        String domainUrl="";
        String secretKey="";
       if (caller.equals(Default.callerType.one)){
            domainUrl = Configurations.duppUrl;
            secretKey = Configurations.duppSecretKey;
        }else if(caller.equals(Default.callerType.two)){
            domainUrl = Configurations.duppSaccUrl;
            secretKey = Configurations.duppSaccSecretKey;
        }
        SignedRequest req = SignedRequest.of(caller,secretKey,params);
        Gson reqGson = new Gson();
        Request request = new Request(domainUrl + service);
        String bodyStr="";
        try {
            bodyStr=reqGson.toJson(req);
            request.setBody(bodyStr.getBytes("UTF-8"));

        } catch (UnsupportedEncodingException e) {
            Logger.error(e, "set body failed.");
        }


        Monitor monitor = MonitorFactory.start("dupp:"+ service);

        Response response = HTTP.POST(request,30);

        monitor.stop();

        JsonParser parser = new JsonParser();
        JsonObject jsonResponse;
        String body = "";
        try {
            body = response.getContent();
            jsonResponse = parser.parse(body).getAsJsonObject();
            String infoFlag = Play.configuration.getProperty("access.dupp.info");
            if(!Utils.isNullOrEmpty(infoFlag) && Boolean.parseBoolean(infoFlag)){
                StackTraceElement invokerElement = invoker.get();
                String invokerDesc = "";

                if(invokerElement != null){
                    Class clazz = Class.forName(invokerElement.getClassName());
                    invokerDesc = invokerElement.getClassName() + "."+invokerElement.getMethodName()+"("+clazz.getSimpleName()+".java:"+invokerElement.getLineNumber()+") ";

                    invoker.remove();
                }
                if(!mute){
                    Logger.info(invokerDesc+"请求："+domainUrl+service+"   Post："+bodyStr);
                    Logger.info("返回："+jsonResponse.get("state"));
                }

            }
        } catch (Exception e) {
            Logger.error(e, "response of dupp not a json string, body: "+body);
            return null;
        }
        if (response.getStatusCode() != 200) {
            Logger.error("DataService.syncGet failed, status: %d, content: %s", response.getStatusCode(), body);
            throw new RuntimeException("get data failed.");
        }
        return jsonResponse;
    }


    private static void setInvoker() {

        //从线程栈中找到调用的位置
        if(Play.mode.isDev()){
            String[] packages = new String[]{
                    "java.lang", "duppentity","utils.DuppUtil","utils.DuppEntityUtil","com.sun.proxy"
            };

            for(StackTraceElement e: Thread.currentThread().getStackTrace()){
                boolean found = true;

                for(String p : packages){
                    String cname = e.getClassName();
                    if(StringUtils.startsWith(cname, p)){
                        found = false;
                        break;
                    }
                }

                if(!found){
                    continue;
                }

                DuppUtil.invoker.set(e);
                break;
            }
        }
    }
}
